package com.naiterui.ehp.bs.doctor.service.user.impl;

import static com.naiterui.ehp.bp.domain.Licence.*;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.constants.EsignServiceProviderEnum;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.Licence;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.esign.ESignUtils;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.doctor.dao.IDoctorDao;
import com.naiterui.ehp.bs.doctor.dao.user.ILicenceDao;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.fegin.EsignFeginClient;
import com.naiterui.ehp.bs.doctor.service.IDoctorService;
import com.naiterui.ehp.bs.doctor.service.ITencentDetectService;
import com.naiterui.ehp.bs.doctor.service.user.IDoctorAuthService;
import com.naiterui.ehp.bs.doctor.service.user.IDoctorRecordService;
import com.naiterui.ehp.bs.doctor.service.user.ILicenceService;
import com.naiterui.ehp.bs.doctor.utils.AdAttchmentHandle;
import com.naiterui.ehp.bs.doctor.utils.AdTencentCloudSdkUtil;
import com.naiterui.ehp.bs.doctor.utils.ImageUrlUtil;
import com.naiterui.ehp.bs.doctor.utils.PropertyValueConstants;
import com.naiterui.ehp.bs.doctor.vo.DrRecordInfoVO;
import com.naiterui.ehp.bs.doctor.vo.IdCardVO;
import com.naiterui.ehp.bs.doctor.vo.LicenceVO;
import com.naiterui.ehp.bs.doctor.vo.LicenseNewParam;
import com.naiterui.ehp.bs.doctor.vo.LicenseParam;
import com.naiterui.ehp.bs.doctor.vo.MedicalLicenseVO;
import com.naiterui.ehp.bs.doctor.vo.QualificationCertificateVO;
import com.naiterui.ehp.bs.doctor.vo.RecordHospitalVO;
import com.naiterui.ehp.bs.doctor.vo.RecordNewParamVO;
import com.naiterui.ehp.bs.doctor.vo.RecordParamVO;
import com.naiterui.ehp.bs.doctor.vo.*;

import cn.hutool.core.util.IdcardUtil;

/**
 * 医生备案相关业务逻辑实现
 *
 * @author Amber
 * @since 1.0.0
 */
@Service
public class AdDoctorRecordServiceImpl implements IDoctorRecordService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AdDoctorRecordServiceImpl.class);

    public static final String SEAL_PATH_PRE_DR = ConfigUtil.getString("esign.seal.path") + "dr/";

    @Autowired
    private IDoctorService doctorService;

    @Autowired
    private ILicenceService licenceService;

    @Autowired
    private ILicenceDao licenceDao;

    @Autowired
    private EsignFeginClient esignFeginClient;

    /**
     * 处理系统中的文件上传和下载的公共服务类
     */
    @Autowired
    private AdAttchmentHandle adAttchmentHandle;
    @Autowired
    private ITencentDetectService tencentDetectService;
    @Value("${file.base.prefix}")
    private String fileBasePath;
    @Autowired
    private IDoctorAuthService doctorAuthService;
    @Autowired
    private IDoctorDao doctorDao;

    @Value("${ehp.domain.img}")
    private String imgDomain;

    public static final String HOSPITAL_NAME = ConfigUtil.getString("ehp.hospital.name");

    @Override
    public RecordHospitalVO getDoctorRecordHospital(long doctorId) throws BusinessException {

        // TODO 废弃逻辑，医师多点职业备案医院固定配置读取
        return new RecordHospitalVO(1, HOSPITAL_NAME);

    }

    @Override
    public RecordHospitalVO getRecordHospitalById(int id) {

        // TODO 废弃逻辑，医师多点职业备案医院固定配置读取
        return new RecordHospitalVO(id, HOSPITAL_NAME);
    }

    @Override
    public DrRecordInfoVO getRecord(long doctorId) throws BusinessException {

        // 这里获取医生，主要是看医生的状态，是不是存在医生，医生账户是不是被禁用
        Doctor doctor = doctorService.get(doctorId);

        Map<Integer, LicenceVO> licenceVOMap = licenceService
                .getLicencesByType(doctorId, DOCTOR_LICENCE_TYPE_IDCARD, DOCTOR_LICENCE_TYPE_TITLECERTIFICATE,
                                   DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE, DOCTOR_LICENCE_TYPE_MEDICAL, DOCTOR_LICENCE_TYPE_EMCARD);

        DrRecordInfoVO drRecordInfoVO = new DrRecordInfoVO();

        drRecordInfoVO.setDoctorId(doctorId);// 医生ID

        String sealUrl = ConfigUtil.getString("img.hosts");
        if (StringUtils.isNotBlank(doctor.getSealImage())) {
            drRecordInfoVO.setSealImage(sealUrl + doctor.getSealImage());
        }

        LicenceVO idCardVO = licenceVOMap.get(DOCTOR_LICENCE_TYPE_IDCARD);

        if (idCardVO != null) {
            drRecordInfoVO.setIdCard((IdCardVO) idCardVO);
        }

        String headUrl = doctor.getHeadUrl();
        if(StringUtils.isNotBlank(headUrl)){
            drRecordInfoVO.setHeadUrl(ImageUrlUtil.getImagePath(headUrl));
        }
        LicenceVO licenceVO = licenceVOMap.get(DOCTOR_LICENCE_TYPE_TITLECERTIFICATE);
        if (licenceVO != null && licenceVO.getUrls() != null && !licenceVO.getUrls().isEmpty()) {
            // 其实这里只有一个图片地址
            drRecordInfoVO.setTitleCertificateUrl(licenceVO.getUrls().get(0));
        }

        // 对医师资格证进行返回对象的封装
        QualificationCertificateVO certificateVO = (QualificationCertificateVO) licenceVOMap.get(DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE);

        if (certificateVO == null) {
            certificateVO = new QualificationCertificateVO();
        }
        certificateVO.setDisplayState(QualificationCertificateVO.DISPLAY_STATE_YES);
        if (certificateVO.getUrls() == null || certificateVO.getUrls().isEmpty()) {
            int status = doctor.getStatus();
            // 申请中/申请通过，并且没有照片信息则不显示
            if (Doctor.AUTH_STATUS_AUDITING == status || Doctor.AUTH_STATUS_SUCCESS == status) {
                certificateVO.setDisplayState(QualificationCertificateVO.DISPLAY_STATE_NO);
            }
        }
        drRecordInfoVO.setQualificationCertificate(certificateVO);

        // 医生执业证 TO YongYang
        Map<Integer, Licence> licenceByDoctorId = licenceDao.getLicenceByDoctorId(doctorId, DOCTOR_LICENCE_TYPE_MEDICAL);
        Licence medicalLicense = licenceByDoctorId.get(DOCTOR_LICENCE_TYPE_MEDICAL);
        MedicalLicenseVO medicalLicenseVO = new MedicalLicenseVO();
        if (medicalLicense != null && !StringUtils.isEmpty(medicalLicense.getUrl())) {
            medicalLicenseVO.setLicenseNumber(medicalLicense.getNumber());
            // medicalLicenseVO.setVersionType(medicalLicense.getVersionType());
            String urls = medicalLicense.getUrl();
            String[] arr = urls.split(",");
            List<String> pics = new ArrayList<>();
            for (String url : arr) {
                pics.add(ImageUrlUtil.getImagePath(url));
            }
            medicalLicenseVO.setUrls(pics);

        }
        drRecordInfoVO.setMedicalLicenseVO(medicalLicenseVO);
        return drRecordInfoVO;

    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public String uploadRecord(RecordParamVO recordParam, LicenseParam licenseParam)
        throws BusinessException, IOException {
        Long doctorId = recordParam.getDoctorId();
        doctorAuthService.updateAuth(doctorId, licenseParam);
        Doctor doctor = doctorService.get(doctorId);

        // 认证状态
        Integer status = doctor.getStatus();

        // 如果是未认证，或者是未提交资料的，那么抛出异常
        /*if (status == Doctor.AUTH_STATUS_NOT_PERFECTION) {

            LOGGER.warn("医生当前认证状态不正确，医生ID：{} 认证状态：{}", doctorId, status);

            throw new BusinessException(ExceptionCodes.WITHDRAWALS_CERT_NOT_COMPLETED);
        }*/

        // 0:未申请备案，1:备案审核中，2:备案成功，3:备案失败
        Integer recordStatus = doctor.getRecordStatus();

        /*if (Doctor.RECORD_STATUS_NOT_APPLY == recordStatus) {
            recordParam.validate(true, doctor.getTitleId());
        }*/

        recordParam.validate(true, doctor.getTitleId());

        // 如果是 审核中和审核成功那么不能修改备案信息
        /*if (recordStatus == Doctor.RECORD_STATUS_EXAMINEING || recordStatus == Doctor.RECORD_STATUS_SUCCESS) {

            LOGGER.warn("医生当前备案状态不能修改备案信息，医生ID：{} 备案状态：{}", doctorId, recordStatus);

            throw new BusinessException(ExceptionCodes.WITHDRAWALS_CERT_NOT_COMPLETED);

        }*/

        String resultSuccess = "成功";
        // 校验实名信息
        //TencentApi.idCardVerification(doctor.getId(), recordParam.getIdNumber(), doctor.getName());
        // 四川CA备案前，校验是否做过人脸并通过
        String serviceId = ESignUtils.getServiceId();

        String idNumber = recordParam.getIdNumber();
        if (EsignServiceProviderEnum.SCCA.getServiceId().equals(serviceId)) {
            AdTencentCloudSdkUtil.FaceSyncVO faceSyncVO = this.tencentDetectService.getFaceSync(doctor.getId());
            if (!faceSyncVO.getResult()) {
                LOGGER.warn("备案申请-人脸识别未通过 doctorId:{}", doctor.getId());
                throw new BusinessException(ExceptionCodes.ILLEGAL_REQUEST, "备案申请需要先完成实名认证");
            }
            if (!faceSyncVO.getIdNo().equals(idNumber)) {
                LOGGER.warn("备案申请-实名身份证号与提交信息不匹配 doctorId:{}, reqIdNo:{}, authIdNo:{}", doctor.getId(), idNumber,
                    faceSyncVO.getIdNo());
                throw new BusinessException(ExceptionCodes.ILLEGAL_REQUEST, "实名身份证号与提交信息不匹配");
            }
            LOGGER.info("已认证实名，开始创建ca账号， doctorId: {}", doctorId);
            String pwd = idNumber.substring(idNumber.length() - 4).toUpperCase();
            esignFeginClient.esignDoctorAdd(doctorId, doctor.getName(), idNumber, doctor.getPhone(), HOSPITAL_NAME,
                doctor.getSealImage(), pwd);
            // 认证通过后改为认证中和备案中
            doctor.setStatus(Doctor.AUTH_STATUS_AUDITING);
            doctor.setRecordStatus(Doctor.RECORD_STATUS_EXAMINEING);
            // 缓存医生设置密码状态
            String statusKey = PropertyValueConstants.DOCTOR_ESIGN_PWD_STATUS_KEY + doctorId;
            RedisUtil.valueOps().set(statusKey, true);
            resultSuccess = String.format(ConfigUtil.getString("scca.apply.success"), pwd);
        }

        // 更新医生备案信息
        licenceService.updateRecord(recordParam);

        // 更新备案状态为备案申请中
        // doctor.setRecordStatus(Doctor.RECORD_STATUS_EXAMINEING);

        // 保存签章图
        if (recordParam.getSealImg() != null) {
            LOGGER.info("上传医生签名图片 doctorId:{}, fileName:{}", doctorId, recordParam.getSealImg().getName());
            // 生成签名印章
            String filepath = SEAL_PATH_PRE_DR + doctorId + "_" + System.currentTimeMillis() + "_o.jpg";
            File signImgfile = new File(filepath);
            FileUtils.forceMkdirParent(signImgfile);
            FileUtils.copyInputStreamToFile(recordParam.getSealImg().getInputStream(), signImgfile);
            String path = filepath.replaceAll(fileBasePath, "");
            doctor.setSealImageOrigin(path);
            // 签章图片处理
            String sealImage = doctorService.processSealImage(doctorId, filepath);
            String sealImagePath = sealImage.replaceAll(fileBasePath, "");
            doctor.setSealImage(sealImagePath);
        }

        // 更新时间
        doctor.setChangedAt(new Date());

        if (StringUtils.isNotBlank(idNumber)) {

            doctor.setGender(this.getGender(idNumber));
        }
        if (StringUtils.isNotBlank(recordParam.getName())) {
            doctor.setName(recordParam.getName());
        }
        // 更新医生信息
        doctorService.update(doctor);
        return resultSuccess;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadRecordNew(RecordNewParamVO recordParam, LicenseNewParam licenseParam)
        throws BusinessException, IOException {
        Long doctorId = recordParam.getDoctorId();
        doctorAuthService.updateAuthNew(doctorId, licenseParam);
        Doctor doctor = doctorService.get(doctorId);

        // 四川CA备案前，校验是否做过人脸并通过
        String serviceId = ESignUtils.getServiceId();

        if (EsignServiceProviderEnum.SCCA.getServiceId().equals(serviceId)) {
            AdTencentCloudSdkUtil.FaceSyncVO faceSyncVO = this.tencentDetectService.getFaceSync(doctor.getId());
            if (!faceSyncVO.getResult()) {
                LOGGER.warn("备案申请-人脸识别未通过 doctorId:{}", doctor.getId());
                throw new BusinessException(ExceptionCodes.ILLEGAL_REQUEST, "备案申请需要先完成实名认证");
            }
            if (!faceSyncVO.getIdNo().equals(recordParam.getIdNumber())) {
                LOGGER.warn("备案申请-实名身份证号与提交信息不匹配 doctorId:{}, reqIdNo:{}, authIdNo:{}", doctor.getId(),
                    recordParam.getIdNumber(), faceSyncVO.getIdNo());
                throw new BusinessException(ExceptionCodes.ILLEGAL_REQUEST, "实名身份证号与提交信息不匹配");
            }
        }

        // 更新医生备案信息
        licenceService.updateRecordNew(recordParam);

        // 更新备案状态为备案申请中
        // doctor.setRecordStatus(Doctor.RECORD_STATUS_EXAMINEING);

        // 保存签章图
        String sealImgUrl = recordParam.getSealImgUrl();
        if (StringUtils.isNotBlank(sealImgUrl)) {
            doctor.setSealImage(sealImgUrl.replaceAll(imgDomain, ""));
        }

        // 更新时间
        doctor.setChangedAt(new Date());

        if (StringUtils.isNotBlank(recordParam.getIdNumber())) {
            doctor.setGender(this.getGender(recordParam.getIdNumber()));
        }
        if (StringUtils.isNotBlank(recordParam.getName())) {
            doctor.setName(recordParam.getName());
        }
        // 更新医生信息
        doctorService.update(doctor);
    }

    /**
     * 根据身份编号获取性别
     *
     * @param idCard 身份编号
     *
     * @return 性别(0 女 1 男 2 未知)
     */
    private int getGender(String idCard) {
        try {
            int genderByIdCard = IdcardUtil.getGenderByIdCard(idCard);
            return genderByIdCard == 1 ? 0 : 1;
        } catch (Exception e) {
            return 2;
        }
    }
}
